package net.mimai.vultrue.bus.utils;

import net.mimai.vultrue.framework.base.databind.EagleObjectMapper;
import net.mimai.vultrue.framework.utils.JudgeUtils;
import net.mimai.vultrue.framework.utils.ObjectMapperUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName HttpClient
 * @Description TODO
 * @Author 方丈
 * @Date 2021/2/27 16:52
 * @Version 1.0.0
 **/
public class HttpClientUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    static final ObjectMapper objectMapper =new EagleObjectMapper(new ObjectMapper());
    /**
     * 模拟浏览器
     * @param url
     * @param params
     * @param extHeader
     * @throws Exception
     */
    public static <T> String post(String url, T params,Map<String,String> extHeader) throws Exception{
        Map<String,String> header2 = buildBrowseHeader();
        Map<String,String>  header =new ImmutableMap.Builder<String,String>().putAll(header2).putAll(extHeader).build();

        OkHttpClient okHttpClient = buildClient();
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        String jsonParams = ObjectMapperUtils.writeAsString(params,objectMapper);
        //logger.info("url:{},jsonParams:{}",url,jsonParams);
        RequestBody requestBody = RequestBody.create(mediaType, jsonParams);
        Request.Builder requestBuilder= new Request.Builder().url(url);
        header.forEach((k,v)->{
            requestBuilder.addHeader(k,v);
        });

        logger.info("process request:{}",url);
        Request request=requestBuilder.post(requestBody).build();
        Response response = okHttpClient.newCall(request).execute();
        String responseData = response.body().string();
        logger.info("receive response:{},httpCode:{}",responseData,response.code());
        return responseData;
    }

    public static String post(String url,Map<String,String> extHeader) throws Exception{
        Map<String,String> header2 = buildBrowseHeader();
        Map<String,String>  header =new ImmutableMap.Builder<String,String>().putAll(header2).putAll(extHeader).build();

        OkHttpClient okHttpClient = buildClient();
        Request.Builder requestBuilder= new Request.Builder().url(url);
        header.forEach((k,v)->{
            requestBuilder.addHeader(k,v);
        });
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        final Request request = requestBuilder.post(RequestBody.create(mediaType,"")).build();
        logger.info("process request:{}",url);
        Response response = okHttpClient.newCall(request).execute();
        String responseData = response.body().string();
        logger.info("receive response:{},httpCode:{}",responseData,response.code());
        return responseData;
    }

    /**
     * 表单形式Post
     * @param url
     * @param params
     * @param extHeader
     * @return
     * @throws Exception
     */
    public static String postForm(String url, Map<String,String> params,Map<String,String> extHeader) throws Exception{
        Map<String,String> header2 = buildBrowseHeader();
        Map<String,String>  header =new ImmutableMap.Builder<String,String>().putAll(header2).putAll(extHeader).build();

        OkHttpClient okHttpClient = buildClient();
        FormBody.Builder builder = new FormBody.Builder();
        if(JudgeUtils.isNotEmpty(params)){
            params.forEach((k,v)->builder.add(k,v));
        }
        Request.Builder  requestBuilder = new Request.Builder().url(url);
        header.forEach((k,v)->{
            requestBuilder.addHeader(k,v);
        });
        logger.info("process request:{}",url);
        Request request=requestBuilder.post(builder.build()).build();
        Response response = okHttpClient.newCall(request).execute();
        String responseData = response.body().string();
        logger.info("receive response:{},httpCode:{}",responseData,response.code());
        return responseData;
    }


    public static String get(String url,Map<String,String> extHeader) throws Exception{
        Map<String,String> header2 = buildBrowseHeader();
        Map<String,String>  header =new ImmutableMap.Builder<String,String>().putAll(header2).putAll(extHeader).build();

        OkHttpClient okHttpClient = buildClient();
        Request.Builder requestBuilder= new Request.Builder().url(url);
        header.forEach((k,v)->{
            requestBuilder.addHeader(k,v);
        });
        final Request request = requestBuilder.get().build();
        logger.info("process request:{}",url);
        Response response = okHttpClient.newCall(request).execute();

        String responseData = response.body().string();
        logger.info("receive response:{},httpCode:{}",responseData,response.code());
        return responseData;
    }


    /**
     * 构建模拟浏览器的请求头
     * @return
     */
    private static Map buildBrowseHeader(){
        return new ImmutableMap.Builder<String,String>()
                .put("Connection","keep-alive")
                .put("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat")
                .build();
    }

    private static OkHttpClient buildClient(){
        return new OkHttpClient.Builder()
                .readTimeout(50, TimeUnit.SECONDS)
                .writeTimeout(20, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .sslSocketFactory(HttpsTrustManager.getSSLSocketFactory(), HttpsTrustManager.getX509TrustManager())
                .hostnameVerifier(HttpsTrustManager.getHostnameVerifier())
                .build();
    }


    public static class HttpsTrustManager{
        //获取这个SSLSocketFactory
        public static SSLSocketFactory getSSLSocketFactory() {
            try {
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, getTrustManager(), new SecureRandom());
                return sslContext.getSocketFactory();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        //获取TrustManager
        private static TrustManager[] getTrustManager() {
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };
            return trustAllCerts;
        }
        //获取HostnameVerifier
        public static HostnameVerifier getHostnameVerifier() {
            return  (s, sslSession) -> true;
        }

        public static X509TrustManager getX509TrustManager() {
            X509TrustManager trustManager = null;
            try {
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init((KeyStore) null);
                TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
                if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                    throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
                }
                trustManager = (X509TrustManager) trustManagers[0];
            } catch (Exception e) {
                e.printStackTrace();
            }

            return trustManager;
        }
    }
}
